﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using LeonardoNews.Models;
using LeonardoNews.Data;
using LeonardoNews.Server.Models.ArticleModels;

namespace LeonardoNews.Repositories
{
    public class UsersRepository
    {
        private const string ValidUsernameChars = "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_1234567890";
        private const int MinUsernameNicknameChars = 4;
        private const int MaxUsernameNicknameChars = 30;

        private const int Sha1CodeLength = 40;

        private static Random rand = new Random();

        private static bool IsUsernameValid(string username)
        {
            if (username == null || username.Length < MinUsernameNicknameChars || username.Length > MaxUsernameNicknameChars)
            {
                return false;
            }
            else if (username.Any(ch => !ValidUsernameChars.Contains(ch)))
            {
                return false;
            }

            return true;
        }

        private static bool IsAuthCodeValid(string authCode)
        {
            if (authCode.Length != Sha1CodeLength)
            {
                return false;
            }

            return true;
        }

        /* public members */

        public static void CreateUser(string username, string authCode)
        {
            if (!IsUsernameValid(username))
            {
                throw new Exception("Invalid username!");
            }

            //if (!IsAuthCodeValid(authCode))
            //{
            //    throw new Exception("Invalid authentication code!");
            //}

            using (NewsContext context = new NewsContext())
            {
                var usernameToLower = username.ToLower();

                var dbUser = context.Users.FirstOrDefault(u => u.Username.ToLower() == usernameToLower);

                if (dbUser != null)
                {
                    if (dbUser.Username.ToLower() == usernameToLower)
                    {
                        throw new Exception("Username already exists");
                    }
                    else
                    {
                        throw new Exception("Nickname already exists");
                    }
                }

                dbUser = new User()
                {
                    Username = usernameToLower,
                    AuthKey = authCode
                };
                context.Users.Add(dbUser);
                context.SaveChanges();
            }

        }

        public static void LoginUser(string username, string authCode)
        {
            var context = new NewsContext();
            using (context)
            {
                var usernameToLower = username.ToLower();
                var user = context.Users.FirstOrDefault(u => u.Username.ToLower() == usernameToLower && u.AuthKey == authCode);
                if (user == null)
                {
                    throw new Exception("Invalid user authentication");
                }
                user.IsLoggedIn = true;
                context.SaveChanges();
            }
        }

        public static int LoginUser(int id)
        {
            var context = new NewsContext();
            using (context)
            {
                var user = context.Users.FirstOrDefault(u => u.ID == id);
                if (user == null)
                {
                    throw new Exception("Invalid user authentication");
                }
                return (int)user.ID;
            }
        }

        public static User LogoutUser(string username)
        {
            var context = new NewsContext();
            using (context)
            {
                var user = context.Users.FirstOrDefault(u => u.Username.ToLower() == username.ToLower());
                if (user == null)
                {
                    throw new Exception("Invalid user authentication");
                }

                context.SaveChanges();

                return new User()
                {
                    ID = user.ID,
                    Role = user.Role
                };
            }
        }

        public static IEnumerable<User> GetAllUsers()
        {
            var context = new NewsContext();
            using (context)
            {
                return context.Users.ToList();
            }
        }
    }
}